/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2010.

	This file is part of the Maxsi Library.

	Maxsi Library is free software: you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or (at your
	option) any later version.

	Maxsi Library is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
	License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with Maxsi Library. If not, see <http://www.gnu.org/licenses/>.

	Maxsi Library
	A powerful Cross-Platform C++ General Purpose Library that allows you to
	efficiently create high-performance and reliable applications.

	MaxsiInterface.cpp
	A system that allows you to easily create different implementations of the
	same virtual base class. It makes the Maxsi Library ridiculously modular.

******************************************************************************/

#include "MaxsiLibrary.h"

BeginMaxsiNamespace

MaxsiInterface::MaxsiInterface() { }
MaxsiInterface::~MaxsiInterface() { }

size_t MaxsiInterface::Implements(char** List, size_t ListSize)
{
	return 0;
}

struct MaxsiInterfaceListEntry
{
	const char* ClassName;
	char* Implements;
	MaxsiImplementationFactor Factory;
	MaxsiImplementationDestructory Destructory;
	MaxsiInterface* StaticInstance;	
	FLAGSL32 Features;
};

List InterfaceList		=	NULL;

MaxsiError AddImplementation(MaxsiImplementationFactor Factory, MaxsiImplementationDestructory Destructory)
{
	// Create a sample instance of this class and ask it how it's going.
	MaxsiInterface*		SampleInstance	=	Factory();

	if ( SampleInstance == NULL ) { return MAXSI_ERROR_MEM_ALLOC_FAIL; }

	FLAGSL32	InterfaceFeatures		=	SampleInstance->GetInterfaceFeatures();

	// Prepare a new entry in our interface table.
	MaxsiInterfaceListEntry Entry;

	// Now do all the asking!
	Entry.ClassName			=	SampleInstance->GetImplementationName();
	Entry.Factory			=	Factory;
	Entry.Destructory		=	Destructory;
	Entry.Features			=	InterfaceFeatures;
	Entry.StaticInstance	=	NULL;

	MAXSI_TODO("This is very limiting only being able to just implement one interface!");	

	SampleInstance->Implements(&Entry.Implements, 1);

	// Find out if this interface is meant to have a static life span, or if it is created on the fly.
	if ( InterfaceFeatures & MAXSI_INTERFACE_STATIC )
	{	
		Entry.StaticInstance	=	SampleInstance;
	}
	else
	{
		Destructory(SampleInstance); SampleInstance = NULL;
	}

	MAXSI_MEMORY_LEAK("InterfaceList is originally a NULL pointer until AddListEntry calls CreateList -- however, there is no DeleteList call, so when the program exits, we got a low priority memory leak.");

	// Now add the entry to the interface table!
	if ( AddListEntry(&InterfaceList, (BYTE*)&Entry, sizeof(Entry)) == false ) { if ( SampleInstance ) { Destructory(SampleInstance); } return MAXSI_ERROR_MEM_ALLOC_FAIL; }
	
	return MAXSI_ERROR_SUCCESS;
}

MaxsiError RemoveImplementation(char* ClassName)
{
	MAXSI_TODO("This function isn't implemented and causes memory leaks!");
	return MAXSI_ERROR_NOT_IMPLEMENTED;
}

MaxsiInterface* GetStaticClass(char* InterfaceName)
{
	if ( InterfaceList == NULL ) { return NULL; }

	size_t	NumImplementations	=	GetListSize(InterfaceList);

	for ( size_t I = 0; I < NumImplementations; I++ )
	{
		MaxsiInterfaceListEntry*	Entry	=	(MaxsiInterfaceListEntry*)GetListEntry(InterfaceList, I);
	
		if ( strcmp(Entry->Implements, InterfaceName) == 0 )
		{
			// This function can only be used to get copies of static interfaces.
			if ( !(Entry->Features & MAXSI_INTERFACE_STATIC) ) { return NULL; }
			
			if ( Entry->StaticInstance == NULL ) { Entry->StaticInstance = Entry->Factory(); }
			return Entry->StaticInstance;
		}
	}

	return NULL;
}

MaxsiInterface* CreateInterface(char* InterfaceName)
{
	if ( InterfaceList == NULL ) { return NULL; }

	size_t	NumImplementations	=	GetListSize(InterfaceList);

	for ( size_t I = 0; I < NumImplementations; I++ )
	{
		MaxsiInterfaceListEntry*	Entry	=	(MaxsiInterfaceListEntry*)GetListEntry(InterfaceList, I);
	
		if ( strcmp(Entry->Implements, InterfaceName) == 0 )
		{
			if ( Entry->Features & MAXSI_INTERFACE_STATIC )
			{
#ifndef Maxsi_Disable_Deprecated
				if ( Entry->StaticInstance == NULL ) { Entry->StaticInstance = Entry->Factory(); }
				return Entry->StaticInstance;
#else
				// This isn't actually harmful, but it will be useful to make all code fail that
				// should use GetStaticClass instead.
				return NULL;
#endif
			}
			return Entry->Factory();
		}
	}

	return NULL;
}

void DeleteInterface(MaxsiInterface* Instance)
{
	if ( InterfaceList == NULL ) { return; }

	size_t	NumImplementations	=	GetListSize(InterfaceList);

	for ( size_t I = 0; I < NumImplementations; I++ )
	{
		MaxsiInterfaceListEntry*	Entry	=	(MaxsiInterfaceListEntry*)GetListEntry(InterfaceList, I);
	
		if ( strcmp(Entry->ClassName, Instance->GetImplementationName()) == 0 ) { Entry->Destructory(Instance); Entry->StaticInstance = NULL; return; }
	}
}

EndMaxsiNamespace

